/*
 * Description:  Guest Manager
 */
#include "guest_manager.h"
#include <filesystem>
#include "log.h"
#include "../common/text_utils.h"

namespace COMMON {

    std::shared_ptr<WINCONTROL::SendToHost> GuestManager::GetSendToHost()
    {
        return m_sendtoHost;
    }
    
    void GuestManager::SetSendToHost(std::shared_ptr<WINCONTROL::SendToHost> m_sendtoHost)
    {
        this->m_sendtoHost = m_sendtoHost;
    }

    void GuestManager::LogProductName(const wchar_t* PRODUCTS[])
    {
        for (int i = 0; PRODUCTS[i] != nullptr; i++) {
            const wchar_t* filePath = PRODUCTS[i];
            std::filesystem::path path(filePath);
            std::string logfile = path.filename().u8string();
            if (!TextUtils::FileExists(TextUtils::WCharToUTF8(filePath))) {
                LOG_ERR("file not exist,Failed to get version for file: {}", logfile);
                continue;
            }
            DWORD dummyHandle;
            DWORD versionSize = GetFileVersionInfoSizeW(filePath, &dummyHandle);
            if (versionSize == 0) {
                LOG_ERR("Failed to get version info size for file: {}", logfile);
                continue;
            }
            std::vector<BYTE> versionData(versionSize);
            if (!GetFileVersionInfoW(filePath, 0, versionSize, versionData.data())) {
                LOG_ERR("Failed to get version info for file:  {}", logfile);
                continue;
            }
            // 获取Translation表
            UINT translationSize = 0;
            LPVOID lpTranslation;
            if (!VerQueryValueW(versionData.data(), L"\\VarFileInfo\\Translation", &lpTranslation, &translationSize)) {
                LOG_ERR("Failed to get lpTranslation info for file:  {}", logfile);
                continue;
            }
            // 构造子块路径 (如040904E4表示英语-UTF8)
            DWORD langCodePage = *((DWORD*)lpTranslation);
            wchar_t subBlockPath[256];
            int result = swprintf_s(subBlockPath, _countof(subBlockPath), L"\\StringFileInfo\\%04X%04X\\ProductVersion",
                                    LOWORD(langCodePage), HIWORD(langCodePage));
            if (result < 0) {
                // 处理错误：缓冲区不足或格式错误 例如清空缓冲区或抛出异常
                LOG_ERR("Failed to get productVersion info for file,swprintf_s error:  {}", logfile);
                continue;
            }
            // 查询ProductVersion
            wchar_t* productVersion = nullptr;
            UINT productVersionLen;
            if (!VerQueryValueW(versionData.data(), subBlockPath, (LPVOID*)&productVersion, &productVersionLen)) {
                LOG_ERR("Failed to get productVersion info for file:  {}", logfile);
                continue;
            }
            LOG_INFO("{} Version: {}", logfile, TextUtils::WCharToUTF8(productVersion));
        }
    }
    
    int GuestManager::LogDriverInfo()
    {
        LOG_INFO("LogDriverInfo Begin.");
        NtQuerySystemInformation_t NtQuerySystemInformation =
            (NtQuerySystemInformation_t)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");
        if (!NtQuerySystemInformation) {
            LOG_INFO("Failed to get NtQuerySystemInformation.");
            return 1;
        }

        ULONG len = 0;
        NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &len);

        PSYSTEM_MODULE_INFORMATION pModuleInfo = (PSYSTEM_MODULE_INFORMATION)malloc(len);
        if (!pModuleInfo) {
            LOG_INFO("Memory allocation failed.");
            return 1;
        }

        if (NtQuerySystemInformation(SystemModuleInformation, pModuleInfo, len, &len) != 0) {
            LOG_INFO("NtQuerySystemInformation failed.");
            free(pModuleInfo);
            return 1;
        }

        LOG_INFO("Loaded Drivers: total {}", pModuleInfo->ModulesCount);
        for (ULONG i = 0; i < pModuleInfo->ModulesCount; i++) {
            PSYSTEM_MODULE mod = &pModuleInfo->Modules[i];
            const char* name = mod->Name + mod->NameOffset;
            LOG_INFO("Driver {} - Name: {} Base: {} Size: {} bytes", i, name, mod->ImageBase, mod->ImageSize);
        }
        LOG_INFO("LogDriverInfo End.");
        free(pModuleInfo);
        return 0;
    }
}